﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Threading;
using System.Reflection.Emit;
using System.Reflection;

namespace Sofire.DataComm.Remoting.Client
{
    /// <summary>
    /// 表示一个远程代理的工厂。
    /// </summary>
    public class ProxyFactory
    {
        private static string _Username;
        /// <summary>
        /// 设置或获取远程服务的默认帐号。
        /// </summary>
        public static string Username
        {
            get
            {
                if(_Username == null) return string.Empty;
                return _Username;
            }
            set
            {
                _Username = value;
            }
        }

        private static string _Password;
        /// <summary>
        /// 设置或获取远程服务的默认密码。
        /// </summary>
        public static string Password
        {
            get
            {
                if(_Password == null) return string.Empty;
                return _Password;
            }
            set
            {
                _Password = value;
            }
        }

        internal static Dictionary<string, RegisterInfo> RegisterDict = new Dictionary<string, RegisterInfo>(StringComparer.OrdinalIgnoreCase);
        internal static object RegisterDictSyncObject = new object();

        internal static string ValidUrl(string address)
        {
            if(!address.StartsWith("tcp://", StringComparison.OrdinalIgnoreCase)) throw new ArgumentException("连接地址起始必须是“tcp://”。");
            address = address.Remove(0, 6);
            if(!address.EndsWith(".v", StringComparison.OrdinalIgnoreCase)) throw new ArgumentException("连接地址结束必须是“.v”。");
            return address;
        }

        internal static void ThrowUnfoundRegistered(string typeName)
        {
            throw new KeyNotFoundException("类型 " + typeName + " 尚未注册！");
        }

        /// <summary>
        /// 注册与远程交互的信息。
        /// </summary>
        /// <param name="name">注册信息的标识名称。</param>
        /// <param name="channelType">服务契约的类型。</param>
        /// <param name="address">服务的地址。</param>
        /// <returns>返回注册成功的信息。如果注册标识名称已存在，则替换原有注册信息。</returns>
        public static RegisterInfo Register(string name, Type channelType, string address)
        {
            return Register(name, channelType, address, null, null);
        }

        /// <summary>
        /// 注册与远程交互的信息。
        /// </summary>
        /// <param name="name">注册信息的标识名称。</param>
        /// <param name="channelType">服务契约的类型。</param>
        /// <param name="address">服务的地址。</param>
        /// <param name="username">契约用户。可以为 null 值。</param>
        /// <param name="password">契约密码。可以为 null 值。</param>
        /// <returns>返回注册成功的信息。如果注册标识名称已存在，则替换原有注册信息。</returns>
        public static RegisterInfo Register(string name, Type channelType, string address, string username, string password)
        {
            if(name == null) throw new ArgumentNullException("name");
            if(address == null) throw new ArgumentNullException("address");
            if(channelType == null) throw new ArgumentNullException("channelType");
            if(!channelType.IsInterface) throw new ArgumentException("通道类型必须是一个接口类型。", "channelType");

            ValidUrl(address);

            var info = new RegisterInfo(name, channelType, address, username, password);
            lock(RegisterDictSyncObject) RegisterDict[name] = info;
            return info;
        }

        /// <summary>
        /// 查找具有指定标识名称的注册信息。
        /// </summary>
        /// <param name="name">注册信息的标识名称。</param>
        /// <returns>返回查找到的注册信息或一个 null 值。</returns>
        public static RegisterInfo Find(string name)
        {
            if(name == null) throw new ArgumentNullException("name");
            RegisterInfo info;
            lock(RegisterDictSyncObject) RegisterDict.TryGetValue(name, out info);
            return info;
        }

        /// <summary>
        /// 清除所有注册信息。
        /// </summary>
        public static void Refresh()
        {
            lock(RegisterDictSyncObject) RegisterDict.Clear();
        }

        /// <summary>
        /// 注销指定类型的注册信息。
        /// </summary>
        /// <param name="name">注册信息的标识名称。</param>
        /// <returns>如果注册列表中含有指定契约类型，并移除成功则返回 true，否则返回 false。</returns>
        public static bool Unregister(string name)
        {
            if(name == null) throw new ArgumentNullException("name");
            lock(RegisterDictSyncObject) return RegisterDict.Remove(name);
        }

        /// <summary>
        /// 创建不限定类型的服务实例。
        /// </summary>
        /// <param name="name">注册信息的标识名称。</param>
        /// <returns>返回一个远程交互的服务实例。</returns>
        public static object CreateObject(string name)
        {
            if(name == null) throw new ArgumentNullException("name");
            RegisterInfo registerInfo = Find(name);
            if(registerInfo == null) ThrowUnfoundRegistered(name);
            return registerInfo.CreateInstance();
        }

        /// <summary>
        /// 创建不限定类型的服务实例。
        /// </summary>
        /// <param name="registerInfo">注册信息。</param>
        /// <returns>返回一个远程交互的服务实例。</returns>
        public static object CreateObject(RegisterInfo registerInfo)
        {
            if(registerInfo == null) throw new ArgumentNullException("registerInfo");
            return registerInfo.CreateInstance();
        }

        /// <summary>
        /// 关闭并销毁通道。
        /// </summary>
        /// <param name="channel">等待销毁的通道。</param>
        public static void Destroy(object channel)
        {
            (channel as IDisposable).Dispose();
        }
    }

    /// <summary>
    /// 表示一个远程代理的工厂。
    /// </summary>
    /// <typeparam name="TChannel">服务契约的类型。</typeparam>
    public class ProxyFactory<TChannel> : ProxyFactory where TChannel : class
    {
        private readonly static Type ChannelType = typeof(TChannel);

        /// <summary>
        /// 创建指定泛型类型的服务实例。
        /// </summary>
        /// <returns>返回一个远程交互的服务实例。</returns>
        public static TChannel Create()
        {
            var type = typeof(TChannel);
            RegisterInfo registerInfo = null;
            lock(RegisterDictSyncObject)
            {
                if(RegisterDict.Count > 0)
                    registerInfo = RegisterDict.Values.First((r) => r.ChannelType == type);
            }
            if(registerInfo == null) ThrowUnfoundRegistered(type.FullName);
            return registerInfo.CreateInstance() as TChannel;
        }

        /// <summary>
        /// 创建指定泛型类型的服务实例。
        /// </summary>
        /// <param name="name">注册信息的标识名称。</param>
        /// <returns>返回一个远程交互的服务实例。</returns>
        public static TChannel Create(string name)
        {
            return CreateObject(name) as TChannel;
        }

        /// <summary>
        /// 创建指定泛型类型的服务实例。
        /// </summary>
        /// <param name="registerInfo">注册信息。</param>
        /// <returns>返回一个远程交互的服务实例。</returns>
        public static TChannel Create(RegisterInfo registerInfo)
        {
            return CreateObject(registerInfo) as TChannel;
        }

        /// <summary>
        /// 注册与远程交互的信息。
        /// </summary>
        /// <param name="address">服务的地址。</param>
        /// <returns>返回注册成功的信息。如果注册标识名称已存在，则替换原有注册信息。</returns>
        public static RegisterInfo Register(string address)
        {
            return Register(ChannelType.FullName, ChannelType, address, null, null);
        }

        /// <summary>
        /// 注册与远程交互的信息。
        /// </summary>
        /// <param name="name">注册信息的标识名称。</param>
        /// <param name="address">服务的地址。</param>
        /// <returns>返回注册成功的信息。如果注册标识名称已存在，则替换原有注册信息。</returns>
        public static RegisterInfo Register(string name, string address)
        {
            return Register(name, ChannelType, address, null, null);
        }

        /// <summary>
        /// 注册与远程交互的信息。
        /// </summary>
        /// <param name="name">注册信息的标识名称。</param>
        /// <param name="address">服务的地址。</param>
        /// <param name="username">契约用户。可以为 null 值。</param>
        /// <param name="password">契约密码。可以为 null 值。</param>
        /// <returns>返回注册成功的信息。如果注册标识名称已存在，则替换原有注册信息。</returns>
        public static RegisterInfo Register(string name, string address, string username, string password)
        {
            return Register(name, ChannelType, address, username, password);
        }

        /// <summary>
        /// 创建并执行服务实例，并在结束后关闭该服务。
        /// </summary>
        /// <param name="action">执行的内容。</param>
        public static void Remote(Action<TChannel> action)
        {
            TChannel channel = null;
            try
            {
                channel = Create();
                action(channel);
            }
            finally
            {
                if(channel != null) (channel as IDisposable).Dispose();
            }
        }

        /// <summary>
        /// 创建并执行服务实例，并在结束后关闭该服务。
        /// </summary>
        /// <typeparam name="TResult">返回值的类型。</typeparam>
        /// <param name="func">执行的内容。</param>
        /// <returns>返回一个 <typeparamref name="TResult" /> 的实例。</returns>
        public static TResult Remote<TResult>(Func<TChannel, TResult> func)
        {
            TChannel channel = null;
            try
            {
                channel = Create();
                return func(channel);
            }
            finally
            {
                if(channel != null) (channel as IDisposable).Dispose();
            }
        }

    }
}
